#ifndef QUERY_PROCESS_UNITTEST_H_
#define QUERY_PROCESS_UNITTEST_H_

#include "unittest_comm.h"
#include "../process/query_process.h"
#include "../process/bool_query_process.h"
#include "../process/geo_distance_query_process.h"
#include "../process/geo_shape_query_process.h"
#include "../process/match_query_process.h"
#include "../process/range_query_process.h"
#include "../process/term_query_process.h"
#include "../process/vector_query_process.h"
#include "vector_processor.h"

UNITEST_NAMESPACE_BEGIN
template<class T>
  QueryProcess* CreateQueryProcess();

template<>
  QueryProcess* CreateQueryProcess<BoolQueryProcess>(){
    std::string str = "{\"must\":{\"match\":{\"content\":\"京东\"}},\"must_not\":{\"match\":{\"title\":\"公园\"}}}";
    std::istringstream iss(str);
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new BoolQueryProcess(value);
  }

template<>
  QueryProcess* CreateQueryProcess<GeoDistanceQueryProcess>(){
    std::istringstream iss("{\"distance\":\"0.9\",\"gis\":[116.50,39.76]}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new GeoDistanceQueryProcess(value);
  }

template<>
  QueryProcess* CreateQueryProcess<GeoShapeQueryProcess>(){
    std::istringstream iss("{\"wkt_poly\":{\"points\":[{\"lat\":31.339747,\"lon\":121.437271},{\"lat\":31.337291,\"lon\":121.438022},{\"lat\":31.336814,\"lon\":121.435297},{\"lat\":31.339252,\"lon\":121.434524}]}}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new GeoShapeQueryProcess(value);
  }

template<>
  QueryProcess* CreateQueryProcess<MatchQueryProcess>(){
    std::istringstream iss("{\"content\":\"京东\"}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new MatchQueryProcess(value);
  }

template<>
  QueryProcess* CreateQueryProcess<RangeQueryProcess>(){
    std::istringstream iss("{\"weight\":{\"gte\":21,\"lte\":24}}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new RangeQueryProcess(value, E_INDEX_READ_RANGE);
  }

template<>
  QueryProcess* CreateQueryProcess<TermQueryProcess>(){
    std::istringstream iss("{\"weight\":21}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new TermQueryProcess(value);
  }

template<>
  QueryProcess* CreateQueryProcess<VectorQueryProcess>(){
    std::istringstream iss("{\"float_vector\":[0.005653954876242762,0.632130963117687,0.7519577013172226,0.8568273368123129,0.2034335192251041,0.9786219451736441,0.5948105950093241,0.9618089054657426]}");
    Json::Reader reader;
    Json::Value value;
    reader.parse(iss, value, false);
    return new VectorQueryProcess(value);
  }

template<class T>
  class QueryProcessUnitTest : public testing::Test {
  protected:
    QueryProcessUnitTest() : query_process_(CreateQueryProcess<T>()){};
    virtual~ QueryProcessUnitTest() {
      DELETE(query_process_);
    };

    QueryProcess* query_process_;
  };

#if GTEST_HAS_TYPED_TEST_P
  using testing::Types;
  TYPED_TEST_SUITE_P(QueryProcessUnitTest);

  TYPED_TEST_P(QueryProcessUnitTest , ParseContent){
    static char conf_filename[1024] = "../conf/index_read.conf";
    if (!SearchConf::Instance()->ParseConf(conf_filename)) {
        printf("parse conf file error: %s.\n", conf_filename);
    }
    SGlobalConfig &global_cfg = SearchConf::Instance()->GetGlobalConfig();
    if (!SplitManager::Instance()->Init(global_cfg.sWordsPath, global_cfg.sTrainPath, global_cfg.sSplitMode)) {
        printf("SplitManager init error\n");
    }
    if (!DBManager::Instance()->Init(global_cfg)){
        printf("DbManager init error\n");
    }
    RequestContext* component = new RequestContext();
    this->query_process_->SetComponent(component);
    EXPECT_EQ(0, this->query_process_->ParseContent());
    DELETE(component);
    SearchConf::Instance()->Destroy();
    DBManager::Instance()->Destroy();
    SplitManager::Instance()->Destroy();
  }

  REGISTER_TYPED_TEST_SUITE_P(
    QueryProcessUnitTest,  // The first argument is the test case name.
    // The rest of the arguments are the test names.
    ParseContent);
  
  typedef Types<BoolQueryProcess, GeoDistanceQueryProcess, GeoShapeQueryProcess,
  MatchQueryProcess, TermQueryProcess, RangeQueryProcess > 
  QueryProcessImplementations;

  INSTANTIATE_TYPED_TEST_SUITE_P(QueryProcessInstance,           // Instance name
                               QueryProcessUnitTest,                // Test case name
                               QueryProcessImplementations);    // Type list
#endif

UNITEST_NAMESPACE_END
#endif
